package com.cxx.framework.app.security;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import com.cxx.purchasecharge.component.bean.LoginUser;
import com.cxx.purchasecharge.component.bean.PCApplicationContext;
import com.cxx.purchasecharge.component.utils.ComponentConstants;
import com.cxx.purchasecharge.dal.RoleDao;
import com.cxx.purchasecharge.dal.UserDao;

/**
 * Default authentication success handler that sets the CCOW user subject and
 * audits the user login.
 */
public class AuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler implements
                                                                                               InitializingBean
{
    private static final Logger logger = Logger.getLogger (AuthenticationSuccessHandler.class);
    private PCApplicationContext pcContext;
    private RoleDao roleDao;
    private UserDao userDao;

    /*
     * (non-Javadoc)
     * 
     * @see org.springframework.security.web.authentication.
     * SavedRequestAwareAuthenticationSuccessHandler
     * #onAuthenticationSuccess(javax.servlet.http.HttpServletRequest,
     * javax.servlet.http.HttpServletResponse,
     * org.springframework.security.core.Authentication)
     */
    @Override
    public void onAuthenticationSuccess (HttpServletRequest request, HttpServletResponse response,
                                         Authentication authentication) throws IOException, ServletException
    {
        try
        {
            User user = (User) authentication.getPrincipal ();
            String userId = user.getUsername ();
            LoginUser loginUser = new LoginUser ();
            loginUser.setUserId (user.getUsername ());
            loginUser.setAdmin (checkContainAdminAuthority (user.getAuthorities ()));
            fillUser (loginUser);
            pcContext.putLoginUser (loginUser);
            request.getSession ().setAttribute (ComponentConstants.LOGIN_USER, loginUser);
            logger.debug ("User: " + userId + " Login completed");
        }
        catch (Exception e)
        {
            request.getSession ().invalidate ();
            String failureUrl = buildLogonFailureUrl (request);
            logger.debug ("Invalidated session. Redirecting to " + failureUrl);
            this.getRedirectStrategy ().sendRedirect (request, response, failureUrl);
        }

        super.onAuthenticationSuccess (request, response, authentication);
    }

    private List <String> convert (Collection <GrantedAuthority> grantedAuthorities)
    {
        List <String> authorities = new ArrayList <String> ();
        Iterator <GrantedAuthority> iter = grantedAuthorities.iterator ();
        while (iter.hasNext ())
        {
            authorities.add (iter.next ().getAuthority ());
        }
        return authorities;
    }

    private void fillUser (LoginUser loginUser)
    {
        if (null != loginUser && StringUtils.isNotBlank (loginUser.getUserId ()))
        {
            com.cxx.purchasecharge.core.model.persistence.User user = userDao.findByUserId (loginUser.getUserId ());
            if (null != user)
            {
                loginUser.setFullName (user.getLastName () + user.getFirstName ());
            }
        }
    }

    private boolean checkContainAdminAuthority (Collection <GrantedAuthority> grantedAuthorities)
    {
        if (!CollectionUtils.isEmpty (grantedAuthorities))
        {
            Iterator <GrantedAuthority> authorityIterator = grantedAuthorities.iterator ();
            while (authorityIterator.hasNext ())
            {
                GrantedAuthority grantedAuthority = authorityIterator.next ();
                if (roleDao.isSystem (grantedAuthority.getAuthority ()))
                {
                    return true;
                }
            }
        }
        return false;
    }

    private String buildLogonFailureUrl (HttpServletRequest request)
    {
        StringBuilder buff = new StringBuilder ().append (request.getContextPath ()).append ('/').append ("login.do");

        return Utils.getDefaultURL (request, buff.toString (), "authfailed=true");
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     */
    public void afterPropertiesSet () throws Exception
    {
        Assert.notNull(this.userDao, "a UserDao is required");
        Assert.notNull(this.roleDao, "A roleDao is required");
        Assert.notNull(this.pcContext, "A PcContext is required");
    }

    public PCApplicationContext getPcContext ()
    {
        return pcContext;
    }

    public void setPcContext (PCApplicationContext pcContext)
    {
        this.pcContext = pcContext;
    }

    public void setRoleDao(RoleDao roleDao)
    {
        this.roleDao = roleDao;
    }

    public UserDao getUserDao ()
    {
        return userDao;
    }

    public void setUserDao (UserDao userDao)
    {
        this.userDao = userDao;
    }

}
